#include "logic.h"
#include "message_node.hpp"
#include "net_global.h"

#include <cstdint>
#include <mutex>
#include <iostream>

Logic::Logic():_is_stop(false)
{
    register_callback();

    _work_thread = std::thread([this](){
        run();
    });
}

Logic::~Logic()
{
    _is_stop = true;
    _task_cond.notify_one();

    if(_work_thread.joinable())
    {
        _work_thread.join();
    }
}

void Logic::run()
{
    while(true)
    {
        FuncCallBack func;
        Task::ptr task;
        uint16_t msg_id;

        {
            std::unique_lock<std::mutex> lock(_task_mutex);
            _task_cond.wait(lock, [this](){
                if (this->_is_stop || !this->_task_que.empty())
                {
                    return true;
                }
                return false;
            });
    
            if(_is_stop && _task_que.empty())
            {
                return;
            }
    
            task = _task_que.front();
            msg_id = task->msg_id();
            std::cout << "task msg id: " << msg_id << std::endl;

            if(_callback.find(msg_id) == _callback.end())
            {
                std::cout << "no callback for msg id: " << msg_id << std::endl;
                continue;
            }
            
            func = _callback[msg_id];
            _task_que.pop();
        }

        func(task->_session, msg_id, std::string(task->_recv_node->_data, task->_recv_node->_total_len));
    }

}

void Logic::post_task(Task::ptr task)
{
    if(_is_stop)
    {
        std::cout << "logic is stop" << std::endl;
        return;
    }

    std::unique_lock<std::mutex> lock(_task_mutex);
    _task_que.push(task);
    
    if(_task_que.size() == 1)
    {
        _task_cond.notify_one();
    }
}


void Logic::register_callback()
{
    _callback[MSG_TEST] = [this](Session::ptr session, const uint16_t msg_id, const std::string& msg_data){
        hello_world_task(session, msg_id, msg_data);
    };
}

void Logic::hello_world_task(Session::ptr session, const uint16_t msg_id, const std::string& msg_data)
{
    Json::Reader reader;
    Json::Value value;

    std::cout << "msg data: " << msg_data << std::endl;
    if(!reader.parse(msg_data, value))
    {
        std::cout << "parse json error" << std::endl;
        return;
    }

    std::cout << "receive msg id: " << value["id"].asInt() << "\tdata: " 
        << value["data"].asString() << std::endl;

    std::string msg = value.toStyledString();
    session->send(msg.c_str(), msg.length(), MSG_TEST);
}